﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using com.kmer;
using com.kmer.Helper;
using com.kmer.interfaces;

namespace com.kmer.library.Factorys {
	/// <summary>
	/// 把配置信息存储到 Redis
	/// </summary>
	public class RedisConfigurationFactory : IConfigurationFactory {

		private static RedisClient _client;
		private static RedisClient GetClient => _client ?? (_client = new RedisClient(6));

		/// <summary>
		/// 命名空间
		/// </summary>
		public string NameSpace { get; set; }

		/// <summary>
		/// 得到字符串形式的配置值（就是把值转换成字符串）
		/// </summary>
		/// <param name="pKey"></param>
		/// <returns></returns>
		public string GetValue(string pKey) {
			var key = getKey(pKey);
			if (GetClient.KeyExists(key)) {
				return GetClient.GetString(pKey);
			}
			return string.Empty;
		}

		/// <summary>
		/// 设置配置值
		/// 必须是已经存在的 否则设置不成功
		/// </summary>
		/// <param name="pKey"></param>
		/// <param name="pValue"></param>
		/// <returns></returns>
		public IConfigurationFactory SetConfig(string pKey, string pValue) {
			var key = getKey(pKey);
			if (!GetClient.KeyExists(key)) {
				throw new Exception($"{pKey} 不存在");
			}
			var type = Type.GetType(GetClient.GetString($"{key}:type"));
			if (type == typeof(int)) {
				GetClient.SetString(key, int.Parse(pValue));
			} else if (type == typeof(long)) {
				GetClient.SetString(key, long.Parse(pValue));
			} else if (type == typeof(double)) {
				GetClient.SetString(key, double.Parse(pValue));
			} else if (type == typeof(bool)) {
				GetClient.SetString(key, bool.Parse(pValue));
			} else if (type == typeof(string)) {
				GetClient.SetString(key, pValue);
			} else if (type == typeof(DateTime)) {
				GetClient.SetString(key, DateTime.Parse(pValue));
			} else if (type == typeof(decimal)) {
				GetClient.SetDecimal(key, decimal.Parse(pValue));
			}

			return this;
		}

		/// <summary>
		/// 得到配置项目的证实 key
		/// </summary>
		/// <param name="pKey"></param>
		/// <returns></returns>
		protected string getKey(string pKey) {
			if (string.IsNullOrWhiteSpace(NameSpace)) {
				return $"ac:{pKey}";
			}
			if (this.NameSpace.EndsWith(":")) {
				return $"ac:{NameSpace}{pKey}";
			}
			return $"ac:{NameSpace}:{pKey}";
		}

		/// <summary>
		/// 返回所有的可用键值
		/// </summary>
		public IEnumerable<string> AllKey {
			get {
				if (string.IsNullOrWhiteSpace(NameSpace)) {
					return GetClient.GetValuesFromSet($"ack:keys", 0, 999).Select(i => i.ToString());
				}
				if (this.NameSpace.EndsWith(":")) {
					return GetClient.GetValuesFromSet($"ack:{NameSpace}keys", 0, 999).Select(i => i.ToString());
				}
				return GetClient.GetValuesFromSet($"ack:{NameSpace}:keys", 0, 999).Select(i => i.ToString());
			}
		}

		private void SetKey(string pKey) {
			if (string.IsNullOrWhiteSpace(NameSpace)) {
				GetClient.AddValueToSet($"ack:keys", pKey);
			} else if (this.NameSpace.EndsWith(":")) {
				GetClient.AddValueToSet($"ack:{NameSpace}keys", pKey);
			} else {
				GetClient.AddValueToSet($"ack:{NameSpace}:keys", pKey);
			}
		}

		#region Get

		/// <summary>
		/// 获取配置值，如果值不存在则自动创建
		/// </summary>
		/// <param name="pKey"></param>
		/// <param name="pValue"></param>
		/// <returns></returns>
		public int Get(string pKey, int pValue) {
			var key = getKey(pKey);
			if (GetClient.KeyExists(key)) {
				return GetClient.GetInt(key);
			}
			SetKey(pKey);
			GetClient.SetString($"{key}:type", pValue.GetType().ToString());
			GetClient.SetInt(key, pValue);
			return pValue;
		}

		/// <summary>
		/// 获取配置值，如果值不存在则自动创建
		/// </summary>
		/// <param name="pKey"></param>
		/// <param name="pValue"></param>
		/// <returns></returns>
		public string Get(string pKey, string pValue) {
			var key = getKey(pKey);
			if (GetClient.KeyExists(key)) {
				return GetClient.GetString(key);
			}
			SetKey(pKey);
			GetClient.SetString($"{key}:type", pValue.GetType().ToString());
			GetClient.SetString(key, pValue);
			return pValue;
		}

		/// <summary>
		/// 获取配置值，如果值不存在则自动创建
		/// </summary>
		/// <param name="pKey"></param>
		/// <param name="pValue"></param>
		/// <returns></returns>
		public double Get(string pKey, double pValue) {
			var key = getKey(pKey);
			if (GetClient.KeyExists(key)) {
				return GetClient.GetDouble(key);
			}
			SetKey(pKey);
			GetClient.SetString($"{key}:type", pValue.GetType().ToString());
			GetClient.SetString(key, pValue);
			return pValue;
		}

		/// <summary>
		/// 获取配置值，如果值不存在则自动创建
		/// </summary>
		/// <param name="pKey"></param>
		/// <param name="pValue"></param>
		/// <returns></returns>
		public long Get(string pKey, long pValue) {
			var key = getKey(pKey);
			if (GetClient.KeyExists(key)) {
				return GetClient.GetLong(key);
			}
			SetKey(pKey);
			GetClient.SetString($"{key}:type", pValue.GetType().ToString());
			GetClient.SetString(key, pValue);
			return pValue;
		}

		/// <summary>
		/// 获取配置值，如果值不存在则自动创建
		/// </summary>
		/// <param name="pKey"></param>
		/// <param name="pValue"></param>
		/// <returns></returns>
		public decimal Get(string pKey, decimal pValue) {
			var key = getKey(pKey);
			if (GetClient.KeyExists(key)) {
				return GetClient.GetDecimal(key, pValue);
			}
			SetKey(pKey);
			GetClient.SetString($"{key}:type", pValue.GetType().ToString());
			GetClient.SetDecimal(key, pValue);
			return pValue;
		}

		/// <summary>
		/// 获取配置值，如果值不存在则自动创建
		/// </summary>
		/// <param name="pKey"></param>
		/// <param name="pValue"></param>
		/// <returns></returns>
		public DateTime Get(string pKey, DateTime pValue) {
			var key = getKey(pKey);
			if (GetClient.KeyExists(key)) {
				return new DateTime(GetClient.GetLong(key));
			}
			SetKey(pKey);
			GetClient.SetString($"{key}:type", pValue.GetType().ToString());
			GetClient.SetString(key, pValue);
			return pValue;
		}

		/// <summary>
		/// 获取配置值，如果值不存在则自动创建
		/// </summary>
		/// <param name="pKey"></param>
		/// <param name="pValue"></param>
		/// <returns></returns>
		public bool Get(string pKey, bool pValue) {
			var key = getKey(pKey);
			if (GetClient.KeyExists(key)) {
				return (bool)GetClient.GetString(key, pValue);
			}
			SetKey(pKey);
			GetClient.SetString($"{key}:type", pValue.GetType().ToString());
			GetClient.SetString(key, pValue);
			return pValue;
		}

		/// <summary>
		/// 获取配置值，如果值不存在则自动创建
		/// </summary>
		/// <typeparam name="T">可实例化的类</typeparam>
		/// <param name="pKey"></param>
		/// <param name="pValue"></param>
		/// <returns></returns>
		public T Get<T>(string pKey, T pValue) where T : class, new() {
			var key = getKey(pKey);
			if (GetClient.KeyExists(key)) {
				return GetClient.GetString(key).ToString().FromJson<T>();
			}
			SetKey(pKey);
			GetClient.SetString($"{key}:type", pValue.GetType().ToString());
			GetClient.SetString(key, pValue.ToJson());
			return pValue;
		}
		#endregion

		#region Set
		/// <summary>
		/// 设置配置值，如果已经存在则会覆盖
		/// 如果已经存在值且类型不符合则会抛出异常
		/// </summary>
		/// <typeparam name="T"></typeparam>
		/// <param name="pKey"></param>
		/// <param name="pValue"></param>
		/// <returns></returns>
		public IConfigurationFactory Set<T>(string pKey, T pValue) where T : class, new() {
			var key = getKey(pKey);
			SetKey(pKey);
			GetClient.SetString($"{key}:type", pValue.GetType().ToString());
			GetClient.SetString(key, pValue.ToJson());
			return this;
		}

		/// <summary>
		/// 设置配置值，如果已经存在则会覆盖
		/// 如果已经存在值且类型不符合则会抛出异常
		/// </summary>
		/// <param name="pKey"></param>
		/// <param name="pValue"></param>
		/// <returns></returns>
		public IConfigurationFactory Set(string pKey, int pValue) {
			var key = getKey(pKey);
			SetKey(pKey);
			GetClient.SetString($"{key}:type", pValue.GetType().ToString());
			GetClient.SetString(key, pValue);
			return this;
		}

		/// <summary>
		/// 设置配置值，如果已经存在则会覆盖
		/// 如果已经存在值且类型不符合则会抛出异常
		/// </summary>
		/// <param name="pKey"></param>
		/// <param name="pValue"></param>
		/// <returns></returns>
		public IConfigurationFactory Set(string pKey, long pValue) {
			var key = getKey(pKey);
			SetKey(pKey);
			GetClient.SetString($"{key}:type", pValue.GetType().ToString());
			GetClient.SetString(key, pValue);
			return this;
		}

		/// <summary>
		/// 设置配置值，如果已经存在则会覆盖
		/// 如果已经存在值且类型不符合则会抛出异常
		/// </summary>
		/// <param name="pKey"></param>
		/// <param name="pValue"></param>
		/// <returns></returns>
		public IConfigurationFactory Set(string pKey, decimal pValue) {
			var key = getKey(pKey);
			SetKey(pKey);
			GetClient.SetDecimal(key, pValue);
			return this;
		}

		/// <summary>
		/// 设置配置值，如果已经存在则会覆盖
		/// 如果已经存在值且类型不符合则会抛出异常
		/// </summary>
		/// <param name="pKey"></param>
		/// <param name="pValue"></param>
		/// <returns></returns>
		public IConfigurationFactory Set(string pKey, bool pValue) {
			var key = getKey(pKey);
			SetKey(pKey);
			GetClient.SetString($"{key}:type", pValue.GetType().ToString());
			GetClient.SetString(key, pValue);
			return this;
		}

		/// <summary>
		/// 设置配置值，如果已经存在则会覆盖
		/// 如果已经存在值且类型不符合则会抛出异常
		/// </summary>
		/// <param name="pKey"></param>
		/// <param name="pValue"></param>
		/// <returns></returns>
		public IConfigurationFactory Set(string pKey, DateTime pValue) {
			var key = getKey(pKey);
			SetKey(pKey);
			GetClient.SetString($"{key}:type", pValue.GetType().ToString());
			GetClient.SetString(key, pValue);
			return this;
		}

		/// <summary>
		/// 设置配置值，如果已经存在则会覆盖
		/// 如果已经存在值且类型不符合则会抛出异常
		/// </summary>
		/// <param name="pKey"></param>
		/// <param name="pValue"></param>
		/// <returns></returns>
		public IConfigurationFactory Set(string pKey, double pValue) {
			var key = getKey(pKey);
			SetKey(pKey);
			GetClient.SetString($"{key}:type", pValue.GetType().ToString());
			GetClient.SetString(key, pValue);
			return this;
		}

		#endregion
	}
}
